package com.pure.common.singleton;

/**
 * @description: 线程安全、双重判断单例，该类只能返回一个实例
 * @date: 2022-11-09 14:10
 * @since 1.2.0
 **/
public class SingletonPattern {

    // 私有化的构造函数
    private SingletonPattern() {
    }

    // 私有化静态的全局变量，volatile 关键字可以保证多个线程的可见性，但是不能保证原子性。同时它也能禁止指令重排。
    private volatile static SingletonPattern instance;

    // 公有的静态方法
    public static SingletonPattern getInstance() {

        if (null == instance) { // 在加锁之前判断是否为空，可以确保 singleton 不为空的情况下，不用加锁，可以直接返回。
            synchronized (SingletonPattern.class) {
                if (null == instance) { // 是为了防止在多线程并发的情况下，只会实例化一个对象。
                    instance = new SingletonPattern();
                }
            }
        }
        return instance;
    }
    /**
     比如：线程a和线程b同时调用 getInstance 方法，假如同时判断 instance 都为空，这时会同时进行抢锁。
     假如线程a先抢到锁，开始执行 synchronized 关键字包含的代码，此时 线程b 处于等待状态。
     线程a创建完新实例了，释放锁了，此时线程b拿到锁，进入 synchronized 关键字包含的代码，如果没有再判断一次 instance 是否为空，则可能会重复创建实例。
     所以需要在 synchronized 前后两次判断。
     */

    /**
     * @description: JVM 会做一些优化，对代码指令进行重排，重排之后的顺序就变成了下面的样子。
     * @date 2022/11/9 4:12 下午
     * @since 1.2.1
     */
    public static SingletonPattern getInstanceCommandReset() {

        if (null == instance) { // 1
            if (null == instance) { // 3
                synchronized (SingletonPattern.class) { // 2
                    instance = new SingletonPattern(); // 4
                }
            }

        }
        return instance; // 5
    }
}
